home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 5 / MacMania 5.toast / / Internet software / NewsWatcher / NW Source / Source / text.c < prev    next >
Text File  |  1997-01-09  |  29KB  |  1,216 lines

  1. /*----------------------------------------------------------------------------
  2.  
  3.     text.c
  4.  
  5.     This module handles read-only text windows.
  6.     
  7.     Copyright © 1994-1997, Northwestern University.
  8.  
  9. ----------------------------------------------------------------------------*/
  10.  
  11. #include <string.h>
  12. #include <ctype.h>
  13.  
  14. #include "glob.h"
  15. #include "text.h"
  16. #include "menus.h"
  17. #include "tescroll.h"
  18. #include "url.h"
  19. #include "newswatcher.h"
  20. #include "drawutil.h"
  21. #include "windutil.h"
  22. #include "memutil.h"
  23. #include "dialog.h"
  24. #include "teutil.h"
  25. #include "wind.h"
  26. #include "about.h"
  27. #include "dragutil.h"
  28. #include "print.h"
  29. #include "status.h"
  30. #include "fileutil.h"
  31. #include "strutil.h"
  32. #include "sfutil.h"
  33. #include "group.h"
  34. #include "key.h"
  35. #include "ic.h"
  36. #include "help.h"
  37.  
  38.  
  39.  
  40. #define kMinWindowWidth        410            /* minimum window width */
  41.  
  42.  
  43.  
  44. static TEClickLoopUPP gAutoScrollUPP;
  45. static ControlActionUPP gScrollActionUPP;
  46.  
  47.  
  48.  
  49. /*----------------------------------------------------------------------------
  50.     GetTextRect 
  51.     
  52.     Compute the "text" rectangle of a text window
  53.             
  54.     Entry:    wind = pointer to text window.
  55.             
  56.     Exit:    *textRect = text rectangle.
  57.     
  58.     The "text" rectangle is the area of the window where the text is 
  59.     displayed: the window portrect, minus the panel area, minus the scroll
  60.     bars, minus the text margin.
  61. ----------------------------------------------------------------------------*/
  62.  
  63. static void GetTextRect (WindowPtr wind, Rect *textRect)
  64. {
  65.     TWindow **info;
  66.  
  67.     info = (TWindow**)GetWRefCon(wind);
  68.     *textRect = wind->portRect;
  69.     textRect->top += (**info).panelHeight;
  70.     textRect->bottom -= 15;
  71.     textRect->right -= 15;
  72.     InsetRect(textRect, kTextMargin, kTextMargin);
  73. }
  74.  
  75.  
  76.  
  77. /*----------------------------------------------------------------------------
  78.     FixHeight 
  79.     
  80.     Round down window height to an exact multiple of lines.
  81.             
  82.     Entry:    wind = pointer to text window.
  83.             *height = window height.
  84.             
  85.     Exit:    *height = adjusted window height
  86. ----------------------------------------------------------------------------*/
  87.  
  88. static void FixHeight (WindowPtr wind, short *height)
  89. {
  90.     TWindow **info;
  91.     short panelHeight, lineHeight, adjust;
  92.  
  93.     info = (TWindow**)GetWRefCon(wind);
  94.     panelHeight = (**info).panelHeight;
  95.     lineHeight = (**info).lineHeight;
  96.     adjust = panelHeight + 15 + 2*kTextMargin;
  97.     *height = (*height - adjust) / lineHeight * lineHeight + adjust;
  98. }
  99.  
  100.  
  101.  
  102. /*----------------------------------------------------------------------------
  103.     MinHeight 
  104.     
  105.     Compute the minimum height of a text window.
  106.             
  107.     Entry:    wind = pointer to text window.
  108. ----------------------------------------------------------------------------*/
  109.  
  110. static short MinHeight (WindowPtr wind)
  111. {
  112.     TWindow **info;
  113.     short lineHeight, height, extra;
  114.     
  115.     info = (TWindow**)GetWRefCon(wind);
  116.     lineHeight = (**info).lineHeight;
  117.     extra = lineHeight + 15 + 2*kTextMargin;
  118.     if (extra < 65) extra = 65 + lineHeight;
  119.     height = (**info).panelHeight + extra;
  120.     FixHeight(wind, &height);
  121.     return height;
  122. }
  123.  
  124.  
  125.  
  126. /*----------------------------------------------------------------------------
  127.     ScrollAction 
  128.     
  129.     Vertical scroll bar action proc.
  130.  
  131.     Entry:    vScroll = handle to vertical scroll bar control.
  132.             part = part code.
  133. ----------------------------------------------------------------------------*/
  134.  
  135. static pascal void ScrollAction (ControlHandle vScroll, short part)
  136. {
  137.     WindowPtr wind;
  138.     TWindow **info;
  139.     TEHandle theTE;
  140.     
  141.     wind = (**vScroll).contrlOwner;
  142.     info = (TWindow**)GetWRefCon(wind);
  143.     theTE = (**info).theTE;
  144.     TEScrollScrollByPartCode(theTE, vScroll, part);
  145. }
  146.  
  147.  
  148.  
  149. /*----------------------------------------------------------------------------
  150.     AutoScroll 
  151.     
  152.     Handle text window autoscrolling.
  153.             
  154.     Exit:    function result = true
  155. ----------------------------------------------------------------------------*/
  156.  
  157. static pascal Boolean AutoScroll (void)
  158. {
  159.     WindowPtr wind;
  160.     TWindow **info;
  161.     ControlHandle vScroll;
  162.     TEHandle theTE;
  163.  
  164.     wind = MyFrontWindow();
  165.     if (wind == nil) return true;
  166.     info = (TWindow**)GetWRefCon(wind);
  167.     vScroll = (**info).vScroll;
  168.     theTE = (**info).theTE;
  169.     TEScrollAutoScroll(theTE, vScroll);
  170.     return true;
  171. }
  172.  
  173.  
  174.  
  175. /*----------------------------------------------------------------------------
  176.     ResizeContents 
  177.     
  178.     Adjust a text window's contents after a window size change (grow
  179.     or zoom).
  180.             
  181.     Entry:    wind = pointer to text window.
  182. ----------------------------------------------------------------------------*/
  183.  
  184. static void ResizeContents (WindowPtr wind)
  185. {
  186.     TWindow **info;
  187.     short width, height, panelHeight;
  188.     ControlHandle vScroll;
  189.     TEHandle theTE;
  190.     Rect r;
  191.  
  192.     info = (TWindow**)GetWRefCon(wind);
  193.     panelHeight = (**info).panelHeight;
  194.     vScroll = (**info).vScroll;
  195.     theTE = (**info).theTE;
  196.     width = wind->portRect.right;
  197.     height = wind->portRect.bottom;
  198.     
  199.     SetRect(&r, width-15, panelHeight-1, width+1, height-14);
  200.     (**vScroll).contrlRect = r;
  201.     
  202.     GetTextRect(wind, &r);
  203.     (**theTE).viewRect = (**theTE).destRect = r;
  204.     TECalText(theTE);
  205.     SetControlValue(vScroll, 0);
  206.     TEScrollAdjustScrollMax(theTE, vScroll);
  207.     TEScrollScrollSelectionIntoView(theTE, vScroll);
  208.     
  209.     InvalRect(&wind->portRect);
  210. }
  211.  
  212.  
  213.  
  214. /*----------------------------------------------------------------------------
  215.     MakeNewTextWindow
  216.     
  217.     Create a new text window.
  218.     
  219.     Entry:    title = window title, P-format.
  220.             panelHeight = panel height.
  221.             drawPanel = pointer to panel drawing function, or nil if none.
  222.             text = handle to text.
  223.                 
  224.     Exit:    function result = error code.
  225.             *theWindow = pointer to new window.
  226. ----------------------------------------------------------------------------*/
  227.  
  228. OSErr MakeNewTextWindow (StringPtr title, short panelHeight, 
  229.     void (*drawPanel)(WindowPtr), Handle text, WindowPtr *theWindow)
  230. {
  231.     short width, height;
  232.     WindowPtr wind = nil;
  233.     TWindow **info;
  234.     Rect r;
  235.     TEHandle theTE;
  236.     ControlHandle vScroll;
  237.     OSErr err = noErr;
  238.     char state;
  239.     GrafPtr port;
  240.     long len;
  241.     
  242.     MyICReadSharedPrefs(kICScreenFont);
  243.     
  244.     GetPort(&port);
  245.  
  246.     err = CreateNewWindow(kText, title, gPrefs.textFont, gPrefs.textSize, &wind);
  247.     if (err != noErr) return err;
  248.     SetPort(wind);
  249.     info = (TWindow**)GetWRefCon(wind);
  250.  
  251.     (**info).panelHeight = panelHeight;
  252.     (**info).drawPanel = drawPanel;
  253.     width = kMinWindowWidth;
  254.     height = MinHeight(wind);
  255.     PositionNewWindow(wind, width, height);
  256.  
  257.     GetTextRect(wind, &r);
  258.     theTE = TENew(&r, &r);
  259.     (**theTE).clickLoop = gAutoScrollUPP;
  260.     if (gHaveTEOutlineHilite) TEFeatureFlag(teFOutlineHilite, TEBitSet, theTE);
  261.     (**info).theTE = theTE;
  262.     
  263.     SetRect(&r, width-15, panelHeight-1, width+1, height-14); 
  264.     vScroll = NewControl(wind, &r, "\p", true, 0, 0, 0, scrollBarProc, 1);
  265.     (**info).vScroll = vScroll;
  266.     
  267.     state = MyHGetState(text);
  268.     MyHLock(text);
  269.     len = MyGetHandleSize(text);
  270.     if (len > kMaxShort) len = kMaxShort;
  271.     err = MyTESetText(*text, len, theTE);
  272.     MyHSetState(text, state);
  273.     if (err != noErr) goto exit;
  274.     
  275.     TESetSelect(0, 0, theTE);
  276.     
  277.     err = DoZoom(wind, inZoomOut);
  278.     if (err != noErr) goto exit;
  279.     
  280.     TEScrollAdjustScrollMax(theTE, vScroll);
  281.     MyShowWindow(wind);
  282.     *theWindow = wind;
  283.     SetPort(port);
  284.     return noErr;
  285.     
  286. exit:
  287.  
  288.     DoClose(wind);
  289.     SetPort(port);
  290.     return err;
  291. }
  292.  
  293.  
  294.  
  295. /*----------------------------------------------------------------------------
  296.     CheckTextWindowAlreadyOpen
  297.     
  298.     Check to see if a text window is already open, and if it is, bring it to
  299.     the front.
  300.     
  301.     Entry:    title = window title, P-format.
  302.                 
  303.     Exit:    function result = true if already open window brought to front.
  304. ----------------------------------------------------------------------------*/
  305.  
  306. Boolean CheckTextWindowAlreadyOpen (StringPtr title)
  307. {
  308.     WindowPtr wind;
  309.     Str255 windTitle;
  310.     TWindowKind kind;
  311.     
  312.     wind = FrontWindow();
  313.     while (wind != nil) {
  314.         kind = GetMyWindowKind(wind);
  315.         if (kind == kText) {
  316.             GetWTitle(wind, windTitle);
  317.             if (EqualString(windTitle, title, false, false)) {
  318.                 MySelectWindow(wind);
  319.                 return true;
  320.             }
  321.         }
  322.         wind = (WindowPtr)(((WindowPeek)wind)->nextWindow);
  323.     }
  324.     return false;
  325. }
  326.  
  327.  
  328.  
  329. /*----------------------------------------------------------------------------
  330.     Find 
  331.     
  332.     Search a text window for a pattern.
  333.             
  334.     Entry:    wind = pointer to text window.
  335.             offset = offset into text to begin search.
  336.             gFindPattern = pattern.
  337.     
  338.     Exit:    function result = error code.
  339. ----------------------------------------------------------------------------*/
  340.  
  341. static OSErr Find (WindowPtr wind, short offset)
  342. {
  343.     TWindow **info;
  344.     TEHandle theTE;
  345.     Handle hText;
  346.     short len;
  347.     char state;
  348.     long matchOffset;
  349.     OSErr err = noErr;
  350.     
  351.     info = (TWindow**)GetWRefCon(wind);
  352.     theTE = (**info).theTE;
  353.     hText = (**theTE).hText;
  354.     len = (**theTE).teLength - offset;
  355.     state = MyHGetState(hText);
  356.     MyHLock(hText);
  357.     err = MyNSubstringSearch(*hText+offset, gFindPattern, len, &matchOffset, 
  358.         GiveTime);
  359.     MyHSetState(hText, state);
  360.     if (err != noErr) return err;
  361.     if (matchOffset == -1) {
  362.         SysBeep(0);
  363.     } else {
  364.         offset += matchOffset;
  365.         TESetSelect(offset, offset + strlen(gFindPattern), theTE);
  366.         TEScrollScrollToMiddle(theTE, offset, (**info).vScroll);
  367.     }
  368.     return noErr;
  369. }
  370.  
  371.  
  372.  
  373. /*----------------------------------------------------------------------------
  374.     DoSave 
  375.     
  376.     Handle the "Save" command.
  377.             
  378.     Entry:    wind = pointer to text window.
  379.             modifiers = modifiers field from event record.
  380.     
  381.     Exit:    function result = error code.
  382. ----------------------------------------------------------------------------*/
  383.  
  384. static OSErr DoSave (WindowPtr wind, short modifiers)
  385. {
  386.     Str255 title;
  387.     Str31 fileName;
  388.     StandardFileReply reply;
  389.     Str255 prompt;
  390.     OSErr err = noErr;
  391.     TWindow **info;
  392.     Handle text;
  393.     long start, end;
  394.     TEHandle theTE;
  395.     char state;
  396.     short refNum = 0;
  397.     Boolean empty;
  398.     Boolean needCR;
  399.     long length;
  400.     char *p;
  401.     
  402.     MyICReadSharedPrefs(kICeditorHelper);
  403.  
  404.     GetWTitle(wind, title);
  405.     MakeLegalFileName(title, fileName);
  406.     GetPString(kStrSaveFileAsPrompt, prompt);
  407.     MyStandardPutFile(prompt, fileName, &reply,
  408.         gPrefs.savedArtDefaultFolder ? gPrefs.savedArtDefaultFolderAlias : nil);
  409.     if (!reply.sfGood) return userCanceledErr;
  410.     info = (TWindow**)GetWRefCon(wind);
  411.     theTE = (**info).theTE;
  412.     text = (**theTE).hText;
  413.     if ((modifiers & shiftKey) == 0) {
  414.         start = 0;
  415.         end = MyGetHandleSize(text);
  416.     } else {
  417.         start = (**theTE).selStart;
  418.         end = (**theTE).selEnd;
  419.     }
  420.     
  421.     state = MyHGetState(text);
  422.  
  423.     err = OpenDataForkWriteCreateIfMissing(&reply.sfFile, gPrefs.savedArtCreator, 'TEXT',
  424.         reply.sfScript, false, &refNum, &empty);
  425.     if (err != noErr) goto exit;
  426.  
  427.     length = end - start;
  428.     MyHLock(text);
  429.     
  430.     for (p = *text + end - 1; p >= *text + start && *p == CR; p--) /* do nothing */;
  431.     p++;
  432.     if (p < *text + end) {
  433.         needCR = false;
  434.         length = p + 1 - *text - start;
  435.     } else {
  436.         needCR = true;
  437.     }
  438.     
  439.     err = FSWrite(refNum, &length, *text + start);
  440.     if (err != noErr) goto exit;
  441.     if (needCR) {
  442.         length = 1;
  443.         err = FSWrite(refNum, &length, CRSTR);
  444.         if (err != noErr) goto exit;
  445.     }
  446.     MyHSetState(text, state);
  447.     MyFSClose(refNum, nil);
  448.     return noErr;
  449.     
  450. exit:
  451.  
  452.     MyHSetState(text, state);
  453.     if (refNum != 0) MyFSClose(refNum, nil);
  454.     return err;
  455. }
  456.  
  457.  
  458.  
  459. /*----------------------------------------------------------------------------
  460.     DoSaveAs
  461.     
  462.     Handle the "Save As" command.
  463.             
  464.     Entry:    wind = pointer to text window.
  465.             modifiers = modifiers field from event record.
  466.     
  467.     Exit:    function result = error code.
  468. ----------------------------------------------------------------------------*/
  469.  
  470. static OSErr DoSaveAs (WindowPtr wind, short modifiers)
  471. {
  472.     return DoSave(wind, modifiers);
  473. }
  474.  
  475.  
  476.  
  477. /*----------------------------------------------------------------------------
  478.     DoPrint 
  479.     
  480.     Handle the "Print" command.
  481.             
  482.     Entry:    wind = pointer to text window.
  483.             modifiers = modifiers field from event record.
  484.             
  485.     Exit:    function result = error code.
  486. ----------------------------------------------------------------------------*/
  487.  
  488. static OSErr DoPrint (WindowPtr wind, short modifiers)
  489. {
  490.     TWindow **info;
  491.     TEHandle theTE;
  492.     Handle text;
  493.     CStr255 title;
  494.     OSErr err = noErr;
  495.     long start, end;
  496.     
  497.     err = StartPrint();
  498.     if (err != noErr) return err;
  499.     
  500.     err = DisplayStatusMessageNumber(kStrPrinting);
  501.     if (err != noErr) return err;
  502.     
  503.     GetWTitle(wind, (StringPtr)title);
  504.     p2cstr((StringPtr)title);
  505.     
  506.     info = (TWindow**)GetWRefCon(wind);
  507.     theTE = (**info).theTE;
  508.     text = (**theTE).hText;
  509.     start = (**theTE).selStart;
  510.     end = (**theTE).selEnd;
  511.     if ((modifiers & shiftKey) == 0 || start >= end) {
  512.         start = 0;
  513.         end = MyGetHandleSize(text);
  514.     }
  515.     
  516.     return PrintText((**theTE).hText, start, end, title);
  517. }
  518.  
  519.  
  520.  
  521. /*----------------------------------------------------------------------------
  522.     DoCopy 
  523.     
  524.     Handle the "Copy" command.
  525.             
  526.     Entry:    wind = pointer to text window.
  527. ----------------------------------------------------------------------------*/
  528.  
  529. static void DoCopy (WindowPtr wind)
  530. {
  531.     TWindow **info;
  532.     TEHandle theTE;
  533.     
  534.     info = (TWindow**)GetWRefCon(wind);
  535.     theTE = (**info).theTE;
  536.     MyTECopy(theTE);
  537. }
  538.  
  539.  
  540.  
  541. /*----------------------------------------------------------------------------
  542.     DoSelectAll 
  543.     
  544.     Handle the "Select All" command.
  545.             
  546.     Entry:    wind = pointer to text window.
  547. ----------------------------------------------------------------------------*/
  548.  
  549. static void DoSelectAll (WindowPtr wind)
  550. {
  551.     TWindow **info;
  552.     TEHandle theTE;
  553.     
  554.     info = (TWindow**)GetWRefCon(wind);
  555.     theTE = (**info).theTE;
  556.     TESetSelect(0, kMaxShort, theTE);
  557. }
  558.  
  559.  
  560.  
  561. /*----------------------------------------------------------------------------
  562.     DoFind 
  563.     
  564.     Handle the "Find" command for a text window.
  565.             
  566.     Entry:    wind = pointer to text window.
  567.     
  568.     Exit:    function result = error code.
  569. ----------------------------------------------------------------------------*/
  570.  
  571. static OSErr DoFind (WindowPtr wind)
  572. {
  573.     TWindow **info;
  574.     TEHandle theTE;
  575.     OSErr err = noErr;
  576.     
  577.     err = DoFindDialog();
  578.     if (err != noErr) return err;
  579.     info = (TWindow**)GetWRefCon(wind);
  580.     theTE = (**info).theTE;
  581.     return Find(wind, gPrefs.startFindAtBeginning ? 0 : (**theTE).selStart);
  582. }
  583.  
  584.  
  585.  
  586. /*----------------------------------------------------------------------------
  587.     DoFindAgain
  588.     
  589.     Handle the "Find Again" command for a text window.
  590.             
  591.     Entry:    wind = pointer to text window.
  592.     
  593.     Exit:    function result = error code.
  594. ----------------------------------------------------------------------------*/
  595.  
  596. static OSErr DoFindAgain (WindowPtr wind)
  597. {
  598.     TWindow **info;
  599.     TEHandle theTE;
  600.     
  601.     info = (TWindow**)GetWRefCon(wind);
  602.     theTE = (**info).theTE;
  603.     return Find(wind, (**theTE).selEnd);
  604. }
  605.  
  606.  
  607.  
  608. /*----------------------------------------------------------------------------
  609.     DoEnterSelection
  610.     
  611.     Handle the "Enter Selection" command for a text window.
  612.             
  613.     Entry:    wind = pointer to text window.
  614.     
  615.     Exit:    function result = error code.
  616. ----------------------------------------------------------------------------*/
  617.  
  618. static OSErr DoEnterSelection (WindowPtr wind)
  619. {
  620.     TWindow **info;
  621.     TEHandle theTE;
  622.     short selStart, selEnd, len;
  623.     Handle hText;
  624.     
  625.     info = (TWindow**)GetWRefCon(wind);
  626.     theTE = (**info).theTE;
  627.     selStart = (**theTE).selStart;
  628.     selEnd = (**theTE).selEnd;
  629.     hText = (**theTE).hText;
  630.     if (selStart >= selEnd || selEnd > selStart + 255) return noErr;
  631.     len = selEnd - selStart;
  632.     BlockMoveData(*hText + selStart, gFindPattern, len);
  633.     gFindPattern[len] = 0;
  634.     return noErr;
  635. }
  636.  
  637.  
  638.  
  639. /*----------------------------------------------------------------------------
  640.     Activate 
  641.     
  642.     Handle an activate event for a text window.
  643.             
  644.     Entry:    wind = pointer to text window.
  645.             act = true to activate, false to deactivate
  646. ----------------------------------------------------------------------------*/
  647.  
  648. static void Activate (WindowPtr wind, Boolean act)
  649. {
  650.     TWindow **info;
  651.     TEHandle theTE;
  652.     ControlHandle vScroll;
  653.     Rect r;
  654.  
  655.     info = (TWindow**)GetWRefCon(wind);
  656.     theTE = (**info).theTE;
  657.     vScroll = (**info).vScroll;
  658.     if (act) {
  659.         ShowControl(vScroll);
  660.         TEActivate(theTE);
  661.     } else {
  662.         HideControl(vScroll);
  663.         TEDeactivate(theTE);
  664.     }
  665.     r = wind->portRect;
  666.     r.top = r.bottom - 15;
  667.     r.left = r.right - 15;
  668.     InvalRect(&r);
  669. }
  670.  
  671.  
  672.  
  673. /*----------------------------------------------------------------------------
  674.     Update 
  675.     
  676.     Handle an update event for a text window.
  677.             
  678.     Entry:    wind = pointer to text window.
  679. ----------------------------------------------------------------------------*/
  680.  
  681. static void Update (WindowPtr wind)
  682. {
  683.     TWindow **info;
  684.     short panelHeight, windWidth;
  685.     Rect r;
  686.     TEHandle theTE;
  687.  
  688.     info = (TWindow**)GetWRefCon(wind);
  689.     panelHeight = (**info).panelHeight;
  690.     theTE = (**info).theTE;
  691.     
  692.     r = wind->portRect;
  693.     r.top += panelHeight;
  694.     ClipRect(&r);
  695.     DrawGrowIcon(wind);
  696.     NoClip();
  697.     
  698.     UpdateControls(wind, wind->visRgn);
  699.     
  700.     if (panelHeight > 0) {
  701.         (*(**info).drawPanel)(wind);
  702.         windWidth = wind->portRect.right - wind->portRect.left;
  703.         MoveTo(0, panelHeight-3);
  704.         LineTo(windWidth, panelHeight-3);
  705.         MoveTo(0, panelHeight-1);
  706.         LineTo(windWidth, panelHeight-1);
  707.     }
  708.     
  709.     TEUpdate(&wind->portRect, theTE);
  710. }
  711.  
  712.  
  713.  
  714. /*----------------------------------------------------------------------------
  715.     Mouse 
  716.     
  717.     Handle a mouse down event in the content area of a text window.
  718.             
  719.     Entry:    wind = pointer to text window.
  720.             where = location of mouse down in local coords.
  721.             modifiers = modifiers field from event record.
  722.             
  723.     Exit:    function result = error code.
  724. ----------------------------------------------------------------------------*/
  725.  
  726. static OSErr Mouse (WindowPtr wind, Point where, short modifiers)
  727. {
  728.     TWindow **info;
  729.     TEHandle theTE;
  730.     Rect viewRect;
  731.     short part, oldVal, dv;
  732.     ControlHandle control, vScroll;
  733.     OSErr err = noErr;
  734.     Boolean dragged = false, trashed;
  735.     short oldSelStart, oldSelEnd;
  736.  
  737.     info = (TWindow**) GetWRefCon(wind);
  738.     theTE = (**info).theTE;
  739.     vScroll = (**info).vScroll;
  740.     viewRect = (**theTE).viewRect;
  741.     InsetRect(&viewRect, -kTextMargin, 0);
  742.     part = FindControl(where, wind, &control);
  743.     if (part != 0 && control == vScroll) {
  744.         if (part == inThumb) {
  745.             oldVal = GetControlValue(vScroll);
  746.             TrackControl(vScroll, where, nil);
  747.             dv = GetControlValue(vScroll) - oldVal;
  748.             if (dv != 0) TEScrollScrollText(theTE, vScroll, -dv);
  749.         } else {
  750.             SetControlReference(vScroll, 0);
  751.             TrackControl(vScroll, where, gScrollActionUPP);
  752.             SetControlReference(vScroll, 1);
  753.             TEScrollAdjustScrollMax(theTE, vScroll);
  754.         }
  755.     } else if (PtInRect(where, &viewRect)) {
  756.         if (gHaveDragMgr) {
  757.             err = DragText(&gCurEvent, where, theTE, &dragged, &trashed);
  758.             if (err != noErr) return err;
  759.         }
  760.         if (wind == FrontWindow() && !dragged) {
  761.             oldSelStart = (**theTE).selStart;
  762.             oldSelEnd = (**theTE).selEnd;
  763.             MyTEClick(where, (modifiers & shiftKey) != 0, theTE);
  764.             err = CommandClick(wind, theTE, oldSelStart, oldSelEnd, modifiers);
  765.             if (err != noErr) return err;
  766.         }
  767.      } else if (where.v < (**info).panelHeight) {
  768.          CheckAboutWindowEasterEgg(wind, where, modifiers);
  769.      }
  770.      return noErr;
  771. }
  772.  
  773.  
  774.  
  775. /*----------------------------------------------------------------------------
  776.     Draggable
  777.     
  778.     Determine whether a mouse down event is on a draggable object in a 
  779.     text window.
  780.     
  781.     Entry:    wind = pointer to text window.
  782.             where = location of mouse down event, in local coordinates.
  783.             modifiers = modifiers field from event record.
  784.             
  785.     Exit:    function result = true if object is draggable.
  786. ----------------------------------------------------------------------------*/
  787.  
  788. static Boolean Draggable (WindowPtr wind, Point where, short modifiers)
  789. {
  790.     TWindow **info;
  791.     TEHandle theTE;
  792.     
  793.     info = (TWindow**)GetWRefCon(wind);
  794.     theTE = (**info).theTE;
  795.     return PtInTEHiliteRgn(where, theTE);
  796. }
  797.  
  798.  
  799.  
  800. /*----------------------------------------------------------------------------
  801.     Key 
  802.     
  803.     Handle a key down event for a text window.
  804.             
  805.     Entry:    wind = pointer to text window.
  806.             theChar = ASCII code of key.
  807.             theKey = keyboard code of key.
  808.             modifiers = modifiers field from event record.
  809.             
  810.     Exit:    function result = error code.
  811. ----------------------------------------------------------------------------*/
  812.  
  813. static OSErr Key (WindowPtr wind, unsigned char theChar, unsigned char theKey, 
  814.     short modifiers)
  815. {
  816.     TWindow **info;
  817.     ControlHandle vScroll;
  818.     TEHandle theTE;
  819.     OSErr err = noErr;
  820.     short scrollIntoView;
  821.     TKeypadKey keypadKey;
  822.     Boolean isArrow;
  823.  
  824.     info = (TWindow**)GetWRefCon(wind);
  825.     vScroll = (**info).vScroll;
  826.     theTE = (**info).theTE;
  827.     isArrow = IsArrowKey(theChar);
  828.     
  829.     if ((modifiers & cmdKey) != 0 && !isArrow) {
  830.         SysBeep(0);
  831.         return noErr;
  832.     }
  833.  
  834.     if (gPrefs.keypadShortcuts && IsKeypadKey(theChar, theKey, &keypadKey)) {
  835.         switch (keypadKey) {
  836.             case kKeypadEqualKey:
  837.                 DoSelectAll(wind);
  838.                 return noErr;
  839.             case kKeypadStarKey:
  840.                 return DoClose(wind);
  841.             case kKeypad1Key:
  842.                 TEScrollScrollByPartCode(theTE, vScroll, kScrollToEnd);
  843.                 return noErr;
  844.             case kKeypad2Key:
  845.                 TEScrollScrollByPartCode(theTE, vScroll, inDownButton);
  846.                 return noErr;
  847.             case kKeypad3Key:
  848.                 TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
  849.                 return noErr;
  850.             case kKeypad7Key:
  851.                 TEScrollScrollByPartCode(theTE, vScroll, kScrollToHome);
  852.                 return noErr;
  853.             case kKeypad8Key:
  854.                 TEScrollScrollByPartCode(theTE, vScroll, inUpButton);
  855.                 return noErr;
  856.             case kKeypad9Key:
  857.                 TEScrollScrollByPartCode(theTE, vScroll, inPageUp);
  858.                 return noErr;
  859.             default:
  860.                 SysBeep(0);
  861.                 return noErr;
  862.         }
  863.     }
  864.     
  865.     if (theChar == pageUpKey) {
  866.         TEScrollScrollByPartCode(theTE, vScroll, inPageUp);
  867.         return noErr;
  868.     }
  869.     if (theChar == pageDownKey) {
  870.         TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
  871.         return noErr;
  872.     }
  873.     if (theChar == homeKey) {
  874.         TEScrollScrollByPartCode(theTE, vScroll, kScrollToHome);
  875.         return noErr;
  876.     }
  877.     if (theChar == endKey) {
  878.         TEScrollScrollByPartCode(theTE, vScroll, kScrollToEnd);
  879.         return noErr;
  880.     }
  881.     
  882.     if (isArrow) {
  883.         TEArrowKey(theChar, modifiers, theTE, 0, &gPrevEvent, &scrollIntoView);
  884.         TEScrollScrollRangeIntoView(theTE, scrollIntoView, scrollIntoView, vScroll);
  885.         return noErr;
  886.     }
  887.     
  888.     if (gPrefs.keyboardShortcuts) {
  889.     
  890.         if (theChar == ' ') {
  891.             TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
  892.             return noErr;
  893.         }
  894.         
  895.         theChar = tolower(theChar);
  896.         
  897.         if (theChar == 'w') {
  898.             return DoClose(wind);
  899.         }
  900.         
  901.         if (theChar == 'a') {
  902.             DoSelectAll(wind);
  903.             return noErr;
  904.         }
  905.         
  906.     }
  907.  
  908.     SysBeep(0);
  909.     
  910.     return noErr;
  911. }
  912.  
  913.  
  914.  
  915. /*----------------------------------------------------------------------------
  916.     Grow 
  917.     
  918.     Handle a mouse down event in the grow box of a text window.
  919.     
  920.     Entry:    wind = pointer to text window.
  921.             where = location of mouse down event, in global coordinates.
  922.             
  923.     Exit:    function result = error code.
  924. ----------------------------------------------------------------------------*/
  925.  
  926. static OSErr Grow (WindowPtr wind, Point where)
  927. {
  928.     Rect sizeRect;
  929.     long size;
  930.     short width, height;
  931.     
  932.     SetRect(&sizeRect, kMinWindowWidth, MinHeight(wind), kMaxShort, kMaxShort);
  933.     size = GrowWindow(wind, where, &sizeRect);
  934.     
  935.     if (size  != 0) {
  936.         width = LoWord(size);
  937.         height = HiWord(size);
  938.         FixHeight(wind, &height);
  939.         SizeWindow(wind, width, height, false);
  940.         ResizeContents(wind);
  941.     }
  942.     
  943.     return noErr;
  944. }
  945.  
  946.  
  947.  
  948. /*----------------------------------------------------------------------------
  949.     Zoom
  950.     
  951.     Zoom a text window.
  952.     
  953.     Entry:    wind = pointer to text window.
  954.             zoomDir = zoom direction = inZoomIn or inZoomOut.
  955.             
  956.     Exit:    function result = error code.
  957. ----------------------------------------------------------------------------*/
  958.  
  959. static OSErr Zoom (WindowPtr wind, short zoomDir)
  960. {
  961.     TWindow **info;
  962.     short width, height, lineHeight, minHeight;
  963.     Rect zoomRect, r;    
  964.     WStateData **wState;
  965.     TEHandle theTE, tempTE;
  966.     Handle tempHandle;
  967.     long longHeight;
  968.  
  969.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  970.     if (zoomDir == inZoomOut) {
  971.         info = (TWindow**)GetWRefCon(wind);
  972.         lineHeight = (**info).lineHeight;
  973.         theTE = (**info).theTE;
  974.         
  975.         width = 75*CharWidth('a') + 2*kTextMargin + 18;
  976.         if (width < kMinWindowWidth) width = kMinWindowWidth;
  977.         
  978.         CalculateZoomRect(wind, width, kMaxShort, &zoomRect, gPrefs.dontCoverFinderIcons);
  979.         SetRect(&r, 0, 0, zoomRect.right - zoomRect.left - 15 - 2*kTextMargin, kMaxShort);
  980.         tempTE = TENew(&r, &r);
  981.         tempHandle = (**tempTE).hText;
  982.         (**tempTE).hText = (**theTE).hText;
  983.         TECalText(tempTE);
  984.         longHeight = (long)TEScrollNumTELines(tempTE) * (long)lineHeight;
  985.         longHeight += (**info).panelHeight + 15 + 2*kTextMargin;
  986.         (**tempTE).hText = tempHandle;
  987.         TEDispose(tempTE);
  988.         if (longHeight > kMaxShort) {
  989.             height = kMaxShort;
  990.         } else {
  991.             height = longHeight;
  992.             minHeight = MinHeight(wind);
  993.             if (height < minHeight) height = minHeight;
  994.         }
  995.         
  996.         CalculateZoomRect(wind, width, height, &zoomRect, gPrefs.dontCoverFinderIcons);
  997.         height = zoomRect.bottom - zoomRect.top;
  998.         FixHeight(wind, &height);
  999.         zoomRect.bottom = zoomRect.top + height;
  1000.         (**wState).stdState = zoomRect;
  1001.         if (WindRectEqualRect(wind, &zoomRect)) return noErr;
  1002.     }
  1003.     
  1004.     EraseRect(&wind->portRect);
  1005.     ZoomWindow(wind, zoomDir, false);
  1006.     ResizeContents(wind);
  1007.     return noErr;
  1008. }
  1009.  
  1010.  
  1011.  
  1012. /*----------------------------------------------------------------------------
  1013.     Command 
  1014.     
  1015.     Handle a command for a text window.
  1016.             
  1017.     Entry:    wind = pointer to text window.
  1018.             menu = the menu.
  1019.             item = the item.
  1020.             modifiers = modifiers field from event record.
  1021.     
  1022.     Exit:    function result = error code.
  1023. ----------------------------------------------------------------------------*/
  1024.  
  1025. static OSErr Command (WindowPtr wind, short menu, short item, short modifiers)
  1026. {
  1027.     OSErr err = noErr;
  1028.  
  1029.     switch (menu) {
  1030.     
  1031.         case kFileMenu:
  1032.         
  1033.             switch (item) {
  1034.                 case kSaveItem:
  1035.                     err = DoSave(wind, modifiers);
  1036.                     break;
  1037.                 case kSaveAsItem:
  1038.                     err = DoSaveAs(wind, modifiers);
  1039.                     break;
  1040.                 case kPrintItem:
  1041.                     err = DoPrint(wind, modifiers);
  1042.                     break;
  1043.             }
  1044.             break;
  1045.             
  1046.         case kEditMenu:
  1047.  
  1048.             switch (item) {
  1049.                 case kCopyItem:
  1050.                     DoCopy(wind);
  1051.                     break;
  1052.                 case kSelectAllItem:
  1053.                     DoSelectAll(wind);
  1054.                     break;
  1055.                 case kFindItem:
  1056.                     err = DoFind(wind);
  1057.                     break;
  1058.                 case kFindAgainItem:
  1059.                     err = DoFindAgain(wind);
  1060.                     break;
  1061.                 case kEnterSelectionItem:
  1062.                     err = DoEnterSelection(wind);
  1063.                     break;
  1064.             }
  1065.             break;
  1066.      }
  1067.      
  1068.      return err;
  1069. }
  1070.  
  1071.  
  1072.  
  1073. /*----------------------------------------------------------------------------
  1074.     Close 
  1075.     
  1076.     Close a text window.
  1077.             
  1078.     Entry:    wind = pointer to text window.
  1079.     
  1080.     Exit:    function result = error code.
  1081. ----------------------------------------------------------------------------*/
  1082.  
  1083. static OSErr Close (WindowPtr wind)
  1084. {
  1085.     TWindow **info;
  1086.  
  1087.     info = (TWindow**)GetWRefCon(wind);
  1088.     
  1089.     if ((**info).theTE != nil) TEDispose((**info).theTE);
  1090.     MyDisposeHandle(info);
  1091.     MyDisposeWindow(wind);
  1092.     return noErr;
  1093. }
  1094.  
  1095.  
  1096.  
  1097. /*----------------------------------------------------------------------------
  1098.     Idle 
  1099.     
  1100.     Handle idle time tasks for a text window.
  1101.             
  1102.     Entry:    wind = pointer to text window.
  1103.     
  1104.     Exit:    cursorRgn = cursor region for WaitNextEvent mouse moved events.
  1105. ----------------------------------------------------------------------------*/
  1106.  
  1107. static void Idle (WindowPtr wind, RgnHandle cursorRgn)
  1108. {
  1109.     TWindow **info;
  1110.     TEHandle theTE;
  1111.     Rect r;
  1112.     Point where;
  1113.     unsigned long fileEnabled, editEnabled, specialEnabled;
  1114.     short selStart, selEnd;
  1115.  
  1116.     info = (TWindow**)GetWRefCon(wind);
  1117.     theTE = (**info).theTE;
  1118.     TEIdle(theTE);
  1119.     
  1120.     r = (**theTE).viewRect;
  1121.     InsetRect(&r, -kTextMargin, 0);
  1122.     LocalToGlobalRect(&r);
  1123.     RectRgn(cursorRgn, &r);
  1124.     if (gHaveDragMgr) SubtractTEHiliteRgn(cursorRgn, theTE);
  1125.     GetMouse(&where);
  1126.     LocalToGlobal(&where);
  1127.     if (PtInRgn(where, cursorRgn)) {
  1128.         SetCursor(&gIBeamCurs);
  1129.     } else {
  1130.         SetCursor(&qd.arrow);
  1131.         ComplementRgn(cursorRgn);
  1132.     }
  1133.     
  1134.     editEnabled = kTextEditEnabled;
  1135.     if (*gFindPattern == 0) editEnabled &= ~kFindAgainMask;
  1136.     selStart = (**theTE).selStart;
  1137.     selEnd = (**theTE).selEnd;
  1138.     if (selStart >= selEnd) {
  1139.         editEnabled &= ~(kCopyMask | kEnterSelectionMask);
  1140.     } else if (selEnd > selStart + 255) {
  1141.         editEnabled &= ~kEnterSelectionMask;
  1142.     }
  1143.     if (gStartupOK) {
  1144.         specialEnabled = kTextSpecialEnabled;
  1145.         SetMenusTo(kAppleAllEnabled, kTextFileEnabled, editEnabled, 
  1146.             kTextNewsEnabled, specialEnabled, kTextWindEnabled);
  1147.     } else {
  1148.         fileEnabled = kTextFileEnabled;
  1149.         fileEnabled &= ~(kNewGroupWindowMask | kOpenMask);
  1150.         SetMenusTo(kAppleAllEnabled, fileEnabled, editEnabled,
  1151.             kStartupBadNewsEnabled, kStartupBadSpecialEnabled, kStartupBadWindEnabled);
  1152.     }
  1153.     
  1154.     /* For shooting screen shots of menus with all items enabled. */
  1155.        
  1156.     #ifdef kDevelopmentVersion
  1157.     {
  1158.         unsigned long all = 0xffffffff;
  1159.         if (gStartupOK) SetMenusTo(all, all, all, all, all, all);
  1160.     }
  1161.     #endif
  1162. }
  1163.  
  1164.  
  1165.  
  1166. /*----------------------------------------------------------------------------
  1167.     Help 
  1168.     
  1169.     Handle help balloons for a text window.
  1170.             
  1171.     Entry:    wind = pointer to text window.
  1172.             where = current mouse location in local coordinates.
  1173. ----------------------------------------------------------------------------*/
  1174.  
  1175. static void Help (WindowPtr wind, Point where)
  1176. {
  1177.     TWindow **info;
  1178.  
  1179.     if (DoSizeBoxAndVerticalScrollBarBalloons(wind, where)) return;
  1180.     info = (TWindow**)GetWRefCon(wind);
  1181.      if (where.v < (**info).panelHeight) {
  1182.          DoAboutWindowIconHelpBalloon(wind, where);
  1183.          return;
  1184.      }
  1185. }
  1186.  
  1187.  
  1188.  
  1189. /*----------------------------------------------------------------------------
  1190.     InitTextDispatchTable 
  1191.     
  1192.     Initialize the dispatch table for text windows.
  1193. ----------------------------------------------------------------------------*/
  1194.  
  1195. void InitTextDispatchTable (void)
  1196. {
  1197.     TDispatch *d;
  1198.     
  1199.     d = &gDispatch[kText];
  1200.     
  1201.     d->activate = Activate;
  1202.     d->update = Update;
  1203.     d->mouse = Mouse;
  1204.     d->draggable = Draggable;
  1205.     d->key = Key;
  1206.     d->grow = Grow;
  1207.     d->zoom = Zoom;
  1208.     d->command = Command;
  1209.     d->close = Close;
  1210.     d->idle = Idle;
  1211.     d->help = Help;
  1212.     
  1213.     gAutoScrollUPP = NewTEClickLoopProc(AutoScroll);
  1214.     gScrollActionUPP = NewControlActionProc(ScrollAction);
  1215. }
  1216.